package com.huanzhidadi.mybatis.plugin;

import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

@Intercepts({
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
})
public class MyPagePlugin implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 获取所有的参数
        Object[] args = invocation.getArgs();
        // MappedStatement: 对mapper映射文件里面元素的封装
        MappedStatement ms = (MappedStatement) args[0];
        Object parameterObject = args[1];
        // BoundSql: 对sql和参数的封装
        BoundSql boundSql = ms.getBoundSql(parameterObject);
        // RowBounds: 封装了逻辑分页的参数，当前页offset，一页数limit
        RowBounds rowBounds = (RowBounds) args[2];
        // 获取原始的sql语句
        String sql = boundSql.getSql();
        // 对原始的sql语句进行包装
        String limitSql = sql;
        // 如果是select语句，且没有limit参数时，添加limit，默认查询语句最多查询5000条记录
        if (sql.trim().toLowerCase().startsWith("select") && !sql.contains("LIMIT") && !sql.contains("limit")) {
            limitSql = sql + " limit 0, 5000";
        }
        // 将分页sql重新封装一个BoundSql
        BoundSql pageBoundSql = new BoundSql(ms.getConfiguration(), limitSql, boundSql.getParameterMappings(), boundSql.getParameterObject());
        // 被代理的对象
        Executor executor = (Executor) invocation.getTarget();
        CacheKey cacheKey = executor.createCacheKey(ms, parameterObject, rowBounds, pageBoundSql);
        // 调用重新封装后的sql，继续执行查询
        return executor.query(ms, parameterObject, rowBounds, (ResultHandler) args[3], cacheKey, pageBoundSql);
    }
}
